<template>
  <div>
    <hr />
    <h1>ak的子组件</h1>
    <h1>vue3的其他语法</h1>
    <h1>reactive:{{ datas.obj.aihao.ball }}</h1>
    <h1>shallowReactive:{{ mydata.obj.aihao.ball }}</h1>
    <h2>{{ state }}</h2>
    <button @click="testToRaw">测试toRaw</button>
    <button @click="testMarkRaw">测试markRaw</button>
    <button @click="change">改变</button>
    <h1>{{ state1.foo }}</h1>
    <button @click="update">改变foo</button>
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  ref,
  shallowReactive,
  shallowRef,
  readonly,
  shallowReadonly,
  toRaw,
  markRaw,
  toRef,
  inject,
  isRef,
  isReactive,
  isReadonly,
  isProxy
} from 'vue'
// readonly:
// 深度只读数据
// 获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理。
// 只读代理是深层的：访问的任何嵌套 property 也是只读的。
// shallowReadonly
// 浅只读数据
// 创建一个代理，使其自身的 property 为只读，但不执行嵌套对象的深度只读转换
// 应用场景:
// 在某些特定情况下, 我们可能不希望对数据进行更新的操作, 那就可以包装生成一个只读代理对象来读取数据, 而不能修改或删除
export default defineComponent({
  setup (props) {
    let liobj = reactive({
      kname: '面试官'
    })
    //inject 接受父辈组件传参
    let color: any = inject('color')
    console.log(color)
    console.log(color.value) //color.value使用inject接受的参数

    // readonly深度只读  shallowReadonly 浅度只读
    let rlist = readonly(liobj)
    liobj.kname = '你好'
    // rlist.kname = '哈哈哈' //只读属性不能修改
    let datas = reactive({
      obj: {
        age: 18,
        aihao: {
          ball: 1
        }
      }
    })

    //  isRef: 检查一个值是否为一个 ref 对象
    // isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
    // isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
    // isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
    let cc = ref('aa')
    console.log('---', isRef(cc))
    console.log('---', isReactive(datas))

    //shallowReactive : 只处理了对象内最外层属性的响应式(也就是浅响应式)
    //     一般情况下使用ref和reactive即可
    // 如果有一个对象数据, 结构比较深, 但变化时只是外层属性变化 ===> shallowReactive
    // 如果有一个对象数据, 后面会产生新的对象来替换 ===> shallowRef
    interface Ilist {
      name: number
      age: any
    }
    let listData = ref<Ilist>({ name: 1, age: 88 })
    let listObj = shallowRef<Ilist>({ name: 2, age: 99 })
    listObj.value = { name: 24, age: 999 }

    //
    let mydata = shallowReactive({
      obj: {
        age: 18,
        aihao: {
          ball: 1
        }
      }
    })
    //
    //  toRaw 与 markRaw
    // toRaw 返回由 reactive 或 readonly 方法转换成响应式代理的普通对象。
    //这是一个还原方法，可用于临时读取，访问不会被代理/跟踪，写入时也不会触发界面更新。
    const state = reactive<any>({
      name: 'tom',
      age: 25
    })

    const testToRaw = () => {
      const user = toRaw(state)
      user.age++ // 界面不会更新
    }

    const testMarkRaw = () => {
      const likes = ['a', 'b']
      // state.likes = likes
      state.likes = markRaw(likes) // likes数组就不再是响应式的了
      setTimeout(() => {
        state.likes[0] += '--'
      }, 1000)
    }
    let change = () => {
      datas.obj.aihao = {
        ball: 88
      }
      mydata.obj.aihao = {
        ball: 99
      }
    }
    // markRaw
    // 标记一个对象，使其永远不会转换为代理。返回对象本身
    // 应用场景:
    // 有些值不应被设置为响应式的，例如复杂的第三方类实例或 Vue 组件对象。
    // 当渲染具有不可变数据源的大列表时，跳过代理转换可以提高性能。

    //     为源响应式对象上的某个属性创建一个 ref对象, 二者内部操作的是同一个数据值, 更新时二者是同步的
    // 区别ref: 拷贝了一份新的数据值单独操作, 更新时相互不影响
    // 应用: 当要将 某个prop 的 ref 传递给复合函数时，toRef 很有用
    const state1 = reactive({
      foo: 1,
      bar: 2
    })

    const foo = toRef(state1, 'foo') //toRef 备份的数据 会影响原数据
    const foo2 = ref(state1.foo) //ref 备份 state1的foo不会影响原数据

    const update = () => {
      // state1.foo++
      // foo.value++
      // foo2.value++ // foo和state1中的数据不会更新
    }

    return {
      state1,
      foo,
      foo2,
      update,
      datas,
      mydata,
      change,
      state,
      testToRaw,
      testMarkRaw
    }
  }
})
</script>
